              package com.java.diagnostics.visualizer.postprocessor.vgc.analysis;
              
              import com.java.diagnostics.visualizer.data.DataSet;
              import com.java.diagnostics.visualizer.data.TupleData;
              import com.java.diagnostics.visualizer.data.Variant;
              import com.java.diagnostics.visualizer.data.axes.Axis;
              import com.java.diagnostics.visualizer.data.axes.XDataAxis;
              import com.java.diagnostics.visualizer.data.axes.YDataAxis;
              import com.java.diagnostics.visualizer.parser.vgc.constants.VGCAxes;
              import com.java.diagnostics.visualizer.parser.vgc.converters.ActionUnitConverter;
              import com.java.diagnostics.visualizer.parser.vgc.converters.EventUnitConverter;
              import com.java.diagnostics.visualizer.parser.vgc.converters.GCReasonUnitConverter;
              import com.java.diagnostics.visualizer.parser.vgc.converters.GCScopeUnitConverter;
              import com.java.diagnostics.visualizer.postprocessing.PostProcessor;
              import com.java.diagnostics.visualizer.properties.OutputProperties;
              import java.util.Arrays;
              import java.util.HashMap;
              import java.util.HashSet;
              import java.util.Map;
              import java.util.Set;
              
              public class UnitSelectingPostProcessor
                implements PostProcessor
              {
                private Map<Axis, Double> axesToMinValues = new HashMap();
                private Map<Axis, Double> axesToMaxValues = new HashMap();
                private Map<Axis, Set<String>> axesToAvailableUnits = new HashMap();
              
                private boolean autoScaleUnitsEnabled = true;
              
                private boolean autoScaleUnitsOnlyForFirstVariant = false;
              
                public void postprocess(DataSet dataSet, OutputProperties properties)
                {
                  if (!this.autoScaleUnitsEnabled) {
                    return;
                  }
              
                  if ((this.autoScaleUnitsOnlyForFirstVariant) && (dataSet.getVariants().length > 1)) {
                    return;
                  }
              
                  properties.disableNotifications();
              
                  for (Variant v : dataSet.getVariants()) {
                    for (TupleData tuple : v.getTupleData()) {
                      Axis xAxis = tuple.getXAxis().getAxis();
                      Axis yAxis = tuple.getYAxis().getAxis();
              
                      if (!this.axesToMinValues.containsKey(xAxis)) {
                        this.axesToMinValues.put(xAxis, Double.valueOf(1.7976931348623157E+308D));
                      }
                      if (!this.axesToMinValues.containsKey(yAxis)) {
                        this.axesToMinValues.put(yAxis, Double.valueOf(1.7976931348623157E+308D));
                      }
                      if (!this.axesToMaxValues.containsKey(xAxis)) {
                        this.axesToMaxValues.put(xAxis, Double.valueOf(-1.797693134862316D+308));
                      }
                      if (!this.axesToMaxValues.containsKey(yAxis)) {
                        this.axesToMaxValues.put(yAxis, Double.valueOf(-1.797693134862316D+308));
                      }
                      if (!this.axesToAvailableUnits.containsKey(xAxis)) {
                        this.axesToAvailableUnits.put(xAxis, new HashSet());
                      }
                      if (!this.axesToAvailableUnits.containsKey(yAxis)) {
                        this.axesToAvailableUnits.put(yAxis, new HashSet());
                      }
              
                      double minX = tuple.getMinX(xAxis.getBaseUnitName());
                      double maxX = tuple.getMaxX(xAxis.getBaseUnitName());
                      double minY = tuple.getMinY(yAxis.getBaseUnitName());
                      double maxY = tuple.getMaxY(yAxis.getBaseUnitName());
              
                      this.axesToMinValues.put(xAxis, 
                        Double.valueOf(Math.min(((Double)this.axesToMinValues.get(xAxis)).doubleValue(), 
                        minX)));
                      this.axesToMinValues.put(yAxis, 
                        Double.valueOf(Math.min(((Double)this.axesToMinValues.get(yAxis)).doubleValue(), 
                        minY)));
                      this.axesToMaxValues.put(xAxis, 
                        Double.valueOf(Math.max(((Double)this.axesToMaxValues.get(xAxis)).doubleValue(), 
                        maxX)));
                      this.axesToMaxValues.put(yAxis, 
                        Double.valueOf(Math.max(((Double)this.axesToMaxValues.get(yAxis)).doubleValue(), 
                        maxY)));
              
                      Set allPossibleXUnits = (Set)this.axesToAvailableUnits.get(xAxis);
                      Set allPossibleYUnits = (Set)this.axesToAvailableUnits.get(yAxis);
                      allPossibleXUnits.addAll(Arrays.asList(
                        tuple.getXAxis().getPossibleUnits()));
                      allPossibleYUnits.addAll(Arrays.asList(
                        tuple.getYAxis().getPossibleUnits()));
                    }
              
                  }
              
                  for (Axis axis : this.axesToMinValues.keySet())
                  {
                    double min = ((Double)this.axesToMinValues.get(axis)).doubleValue();
                    double max = ((Double)this.axesToMaxValues.get(axis)).doubleValue();
                    Set possibleUnits = (Set)this.axesToAvailableUnits.get(axis);
                    String units = findSuitableDisplayUnit(axis.getBaseUnitName(), min, 
                      max, possibleUnits);
                    if (units != null)
                    {
                      properties.setDefaultUnits(axis, units);
                    }
                  }
                }
              
                private String findSuitableDisplayUnit(String baseUnitName, double min, double max, Set<String> possibleUnits)
                {
                  double range = max - min;
              
                  if (VGCAxes.MILLISECONDS.equals(baseUnitName))
                  {
                    String selectedUnits = null;
              
                    if (possibleUnits.contains(VGCAxes.MILLISECONDS)) {
                      selectedUnits = VGCAxes.MILLISECONDS;
                    }
                    if ((range > 5000.0D) && 
                      (possibleUnits.contains(VGCAxes.SECONDS))) {
                      selectedUnits = VGCAxes.SECONDS;
                    }
                    if ((range > 300000.0D) && 
                      (possibleUnits.contains(VGCAxes.MINUTES))) {
                      selectedUnits = VGCAxes.MINUTES;
                    }
                    if ((range > 18000000.0D) && 
                      (possibleUnits.contains(VGCAxes.HOURS))) {
                      selectedUnits = VGCAxes.HOURS;
                    }
                    if ((range > 432000000.0D) && (possibleUnits.contains(VGCAxes.DAYS))) {
                      selectedUnits = VGCAxes.DAYS;
                    }
                    return selectedUnits;
                  }
              
                  if (VGCAxes.BYTES.equals(baseUnitName)) {
                    if ((range < 1024.0D) && (possibleUnits.contains(VGCAxes.BYTES)))
                      return VGCAxes.BYTES;
                    if ((range < 1048576.0D) && (possibleUnits.contains(VGCAxes.KB)))
                      return VGCAxes.KB;
                    if ((range < 1073741824.0D) && (possibleUnits.contains(VGCAxes.MB)))
                      return VGCAxes.MB;
                    if (possibleUnits.contains(VGCAxes.GB)) {
                      return VGCAxes.GB;
                    }
                  }
              
                  if (VGCAxes.HASH_SIGN.equals(baseUnitName)) {
                    if ((range < 500.0D) && (possibleUnits.contains(VGCAxes.HASH_SIGN)))
                      return VGCAxes.HASH_SIGN;
                    if (possibleUnits.contains(VGCAxes.HUNDREDS)) {
                      return VGCAxes.HUNDREDS;
                    }
              
                  }
              
                  if ((VGCAxes.ACTIONCODE.equals(baseUnitName)) && (possibleUnits.contains(ActionUnitConverter.UNITS))) {
                    return ActionUnitConverter.UNITS;
                  }
                  if ((VGCAxes.SCOPECODE.equals(baseUnitName)) && (possibleUnits.contains(GCScopeUnitConverter.UNITS))) {
                    return GCScopeUnitConverter.UNITS;
                  }
                  if ((VGCAxes.REASONCODE.equals(baseUnitName)) && (possibleUnits.contains(GCReasonUnitConverter.UNITS))) {
                    return GCReasonUnitConverter.UNITS;
                  }
                  if ((VGCAxes.EVENTCODE.equals(baseUnitName)) && (possibleUnits.contains(EventUnitConverter.UNITS))) {
                    return EventUnitConverter.UNITS;
                  }
                  return null;
                }
              }

